﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;

namespace RayTracing
{
    public class HitRecord
    {
        public float Time { get; set; }
        public Vector3 Normal { get; set; }
        public Color Color { get; set; }
    }

    public abstract class Shape
    {
        public abstract bool Hit(Ray ray, float tMin, float tMax, float time, out HitRecord record);
        public abstract bool ShadowHit(Ray ray, float tMin, float tMax, float time);
    }

    public class Triangle : Shape
    {
        public Vector3 P0 { get; }
        public Vector3 P1 { get; }
        public Vector3 P2 { get; }
        public Color Color { get; }

        public Triangle(Vector3 p0, Vector3 p1, Vector3 p2, Color color)
        {
            P0 = p0;
            P1 = p1;
            P2 = p2;
            Color = color;
        }

        public override bool Hit(Ray ray, float tMin, float tMax, float time, out HitRecord record)
        {
            record = null;

            var tmp1 = P0 - P1;
            var tmp2 = P0 - P2;
            var a = tmp1.X;
            var b = tmp1.Y;
            var c = tmp1.Z;

            var d = tmp2.X;
            var e = tmp2.Y;
            var f = tmp2.Z;

            var g = ray.Direction.X;
            var h = ray.Direction.Y;
            var i = ray.Direction.Z;

            var tmp3 = P0 - ray.Origin;
            var j = tmp3.X;
            var k = tmp3.Y;
            var l = tmp3.Z;

            var eihf = e * i - h * f;
            var gfdi = g * f - d * i;
            var dheg = d * h - e * g;
            var tmp4 = new Vector3(eihf, gfdi, dheg);
            var denom = Vector3.Dot(tmp1, tmp4);
            var beta = Vector3.Dot(tmp3, tmp4) / denom;
            if (beta <= 0.0f || beta >= 1.0f)
                return false;
            var tmp5 = new Vector3(b * l - k * c, j * c - a * l, a * k - j * b);
            var gamma = Vector3.Dot(ray.Direction, tmp5);
            if (gamma <= 0.0f || gamma + beta >= 1.0f)
                return false;
            record = new HitRecord();
            record.Time = -Vector3.Dot(tmp5, tmp2) / denom;
            record.Normal = Vector3.Cross(P0, P1);
            record.Color = Color;
            return true;
        }

        public override bool ShadowHit(Ray ray, float tMin, float tMax, float time)
        {
            return Hit(ray, tMin, tMax, time, out var record);
        }
    }
}
